# -*- coding: utf-8 -*-
from datetime import date, time, timedelta

from django.db import models
from django.db.models import F, Q
from django.core.exceptions import ValidationError


HORA_POR_DEFECTO = time(9)
DIAS_VERIFICACION_ESTADO = 7
MODALIDADES = (
    ('desayuno', u'Con desayuno'),
    ('media pension', u'Media pensión'))


class Categoria(models.Model):
    nombre = models.CharField(max_length=30, unique=True)
    max_huespedes = models.PositiveSmallIntegerField(
        u'Máximo de huespedes')
    tarifa_base = models.DecimalField(max_digits=15, decimal_places=2)

    class Meta:
        verbose_name = u'Categoría'

    def __unicode__(self):
        return self.nombre


class Habitacion(models.Model):
    numero = models.PositiveSmallIntegerField(
            u'Número', unique=True, db_index=True)
    categoria = models.ForeignKey(Categoria, verbose_name=u'Categoría')

    ESTADO_RESERVADA = 'reservado'
    ESTADO_OCUPADA = 'ocupada'
    ESTADO_DISPONIBLE = 'disponible'

    class Meta:
        ordering = 'numero', 'categoria'
        verbose_name = u'Habitación'
        verbose_name_plural = u'Habitaciones'

    def __unicode__(self):
        return u'%d %s' % (self.numero, self.categoria)

    def estado(self, fecha_desde=None, fecha_hasta=None):
        if fecha_desde is None:
            fecha_desde = date.today()
        if fecha_hasta is None:
            fecha_hasta = fecha_desde + timedelta(DIAS_VERIFICACION_ESTADO)
        alquileres = self.alquiler_set.exclude(
            Q(fecha_egreso__lt=fecha_desde)|
            Q(fecha_ingreso__gte=fecha_hasta)).filter(
                Q(fecha_ingreso__gte=fecha_desde,
                  fecha_egreso__gte=fecha_hasta)|
                Q(fecha_ingreso__gte=fecha_desde,
                  fecha_egreso__lte=fecha_hasta)|
                Q(fecha_ingreso__lte=fecha_desde,
                  fecha_egreso__lte=fecha_hasta)|
                Q(fecha_ingreso__lte=fecha_desde,
                  fecha_egreso__gte=fecha_hasta))
        if alquileres.exists():
            return self.ESTADO_OCUPADA
        hoy = date.today()
        if fecha_desde >= hoy:
            reservas = self.reserva_set.exclude(
                Q(duracion_estadia__lte=fecha_desde - F('fecha_ingreso'))|
                Q(fecha_ingreso__gte=fecha_hasta)).filter(
                    Q(fecha_ingreso__gte=fecha_desde,
                      duracion_estadia__lt=fecha_hasta - F('fecha_ingreso'))|
                    Q(fecha_ingreso__gte=fecha_desde,
                     duracion_estadia__gte=fecha_hasta - F('fecha_ingreso'))|
                    Q(fecha_ingreso__lte=fecha_desde,
                     duracion_estadia__gte=fecha_hasta - F('fecha_ingreso'))|
                    Q(fecha_ingreso__lte=fecha_desde,
                     duracion_estadia__lte=fecha_hasta - F('fecha_ingreso')))
            if reservas.exists():
                return self.ESTADO_RESERVADA
        return self.ESTADO_DISPONIBLE


class Modalidad(models.Model):
    nombre = models.CharField(max_length=30, choices=MODALIDADES)
    adicional_tarifa = models.DecimalField(max_digits=15, decimal_places=2)

    class Meta:
        verbose_name_plural = u'Modalidades'

    def __unicode__(self):
        return self.nombre


class Reserva(models.Model):
    solicitado_a = models.ForeignKey('gente.Empleado', null=True)
    fecha_y_hora = models.DateTimeField(auto_now_add=True, editable=False)
    responsable = models.ForeignKey('gente.Cliente')
    fecha_ingreso = models.DateField()
    hora_ingreso_estimada = models.TimeField(
        default=HORA_POR_DEFECTO, null=True)
    habitaciones = models.ManyToManyField(Habitacion)
    cantidad_de_personas = models.PositiveSmallIntegerField()
    duracion_estadia = models.PositiveSmallIntegerField(
            u'Duración de la estadía (en días)')
    modalidad = models.ForeignKey(Modalidad)
    observaciones = models.TextField(blank=True)

    def __unicode__(self):
        return u'Reserva para %s, a nombre de %s' % (
            self.fecha_ingreso, self.responsable)


class Alquiler(models.Model):
    aprobado_por = models.ForeignKey('gente.Empleado', null=True)
    reserva = models.OneToOneField(Reserva, null=True, blank=True)
    cliente = models.ForeignKey('gente.Cliente', null=True, blank=True)
    habitaciones = models.ManyToManyField(Habitacion)
    huespedes = models.ManyToManyField('gente.Huesped')
    fecha_ingreso = models.DateField()
    hora_ingreso = models.TimeField(default=HORA_POR_DEFECTO)
    fecha_egreso = models.DateField()
    hora_egreso = models.TimeField(default=HORA_POR_DEFECTO)
    modalidad = models.ForeignKey(Modalidad, null=True)
    observaciones = models.TextField(blank=True)

    class Meta:
        verbose_name_plural = u'Alquileres'

    def __unicode__(self):
        habitaciones = ', '.join(unicode(h) for h in self.habitaciones.all())
        return u'%s [%s-%s]' % (
            habitaciones, self.fecha_ingreso, self.fecha_egreso)

    def clean(self):
        if self.reserva is None and self.cliente is None:
            raise ValidationError('Debe seleccionar reserva o cliente')
        return super(Alquiler, self).clean()


class Servicio(models.Model):
    nombre = models.CharField(max_length=50, unique=True)
    adicional_tarifa = models.DecimalField(max_digits=15, decimal_places=2)
    alquiler = models.ForeignKey(Alquiler)
    solicitado_a = models.ForeignKey('gente.Empleado', null=True)
